/*
 * Copyright (c) 2009, Hamish Morgan. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the University of Sussex nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
package piccat.view;

import javax.swing.event.ChangeEvent;
import piccat.lib.ImageLoader;
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Stroke;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.event.ChangeListener;
import piccat.model.Picture;

/**
 * A panel that holds and displays an image. It can either be floated in the
 * glass pane, or snapped to the grid.
 *
 * @author Hamish Morgan
 */
public class PictureView extends JPanel {

    private static final Color BACKGROUND_COLOUR = new Color(0, 255, 0, 128);
    private static final Color BORDER_COLOUR = new Color(0, 255, 0, 192);
    private static final Stroke BORDER_STROKE = new BasicStroke(1);
    private final JLabel label;
    private Picture model;
    private ImageIcon icon;
    private PictureChangeHandler pictureChangeHandler;

    public PictureView(Picture model) {
        super();
        pictureChangeHandler = new PictureChangeHandler();
        setLayout(new BorderLayout());
        setAlignmentY(CENTER_ALIGNMENT);
        label = new JLabel();
        label.setHorizontalAlignment(JLabel.CENTER);
        add(label, BorderLayout.CENTER);
        setModel(model);
        setOpaque(false);
    }

    private class PictureChangeHandler implements ChangeListener {

        public void stateChanged(ChangeEvent e) {
            repaint();
        }

    }

    public PictureView() {
        this(null);
    }

    public void setModel(Picture model) {
        if (model == this.model)
            return;

        if(this.model != null) {
            model.removeChangeListener(pictureChangeHandler);
        }

        this.model = model;

        if (this.model != null) {
            model.addChangeListener(pictureChangeHandler);
            final Image image = ImageLoader.getImage(model.getUrl());
            icon = new ImageIcon(image);
            label.setIcon(icon);
        }

    }

    public Picture getModel() {
        return model;
    }

    private Dimension getScaledImageDim(Image im, Dimension bound) {
        final double xRatio = (double) im.getWidth(this) / bound.width;
        final double yRatio = (double) im.getHeight(this) / bound.height;
        if (xRatio >= yRatio)
            return new Dimension(bound.width, -1);
        else
            return new Dimension(-1, bound.height);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (model == null || !model.isCorrect())
            return;
        final Graphics2D g2 = (Graphics2D) g;
        final Color oldColor = g2.getColor();
        final Stroke oldSTroke = g2.getStroke();

        final Insets insets = getInsets();
        final int x = insets.left;
        final int y = insets.top;
        final int w = getWidth() - (insets.left + insets.right) - 1;
        final int h = getHeight() - (insets.bottom + insets.top) - 1;
        int arc = Math.min(w, h) / 4;
        g2.setColor(BACKGROUND_COLOUR);
        g2.fillRoundRect(x, y, w, h, arc, arc);
        g2.setColor(BORDER_COLOUR);
        g2.setStroke(BORDER_STROKE);
        g2.drawRoundRect(x, y, w, h, arc, arc);

        g2.setColor(oldColor);
        g2.setStroke(oldSTroke);
    }

    @Override
    public void setBounds(int x, int y, int width, int height) {

        final int oldX = this.getX();
        final int oldY = this.getY();
        final int oldWidth = this.getWidth();
        final int oldHeight = this.getHeight();

        final boolean resized = (oldWidth != width) || (oldHeight !=
                height);
        final boolean moved = (oldX != x) || (oldY != y);

        // Update the side of the image so it fits inside this component.
        if (resized) {
            final Dimension d = getScaledImageDim(
                    ImageLoader.getImage(model.getUrl()),
                    new Dimension(width, height));
            final Image image = ImageLoader.getImage(model.getUrl(), d);
            icon.setImage(image);
        }

        // Bound the position by the parents dimensions so it can't go off
        // the screen.
        final Container p = getParent();
        if (moved && p != null) {
            final int left = -label.getX();
            final int right = p.getWidth() - icon.getIconWidth() -
                    label.getX();
            final int top = -label.getY();
            final int bottom = p.getHeight() - label.getHeight();

            if (x < left) x = left;
            else if (x > right) x = right;
            if (y < top) y = top;
            else if (y > bottom) y = bottom;
        }

        super.setBounds(x, y, width, height);
    }
}
